//-----------------------------------------------------------------------------
//  File          : dukpt.c
//  Module        :
//  Description   : DUKPT key injection.
//  Author        : Lewis
//  Notes         :
//
// ============================================================================
// | Naming conventions                                                       |
// | ~~~~~~~~~~~~~~~~~~                                                       |
// |        Struct define : Leading T                                         |
// |         Struct/Array : Leading s                                         |
// |             Constant : Leading K                                         |
// |      Global Variable : Leading g  (variable use outside one C file)      |
// |                                                                          |
// |   BYTE( 8 Bits) size : Leading b                                         |
// |   CHAR( 8 Bits) size : Leading c                                         |
// |   WORD(16 Bits) size : Leading w                                         |
// |  DWORD(32 Bits) size : Leading d                                         |
// |    int(32 Bits) size : Leading i                                         |
// | DDWORD(64 Bits) size : Leading dd                                        |
// |              Pointer : Leading p                                         |
// |                                                                          |
// |    Function argument : Leading a                                         |
// |       Local Variable : All lower case                                    |
// |                                                                          |
// | Examples:                                                                |
// |                Array : Leading s, (sb = arrary of byte, etc)             |
// |              Pointer : Leading p, (pb = pointer of byte, etc)            |
// ============================================================================
//
//  Date          Who         Action
//  ------------  ----------- -------------------------------------------------
//  20 Oct  2008  Lewis       Port form CREON KEYDLL.
//  14 Jan  2009  Lewis       Support External Pinpad.
//-----------------------------------------------------------------------------
#include <string.h>
#include "util.h"
#include "system.h"
#include "key2dll.h"
#include "sysutil.h"
#include "secufile.h"
#include "kbdutil.h"
#include "dukpt.h"


//-----------------------------------------------------------------------------
//    Globals
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//    Globals
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//    Constants
//-----------------------------------------------------------------------------

//*****************************************************************************
//  Function        : KeyInjectDukpt
//  Description     : Inject DUKPT initial key
//  Input           : aKeyStr;   // pointer to key data
//                    // mode + keyidx + 16B key + 10B KSN + 2B KVC (optional)
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
WORD DukptKeyInject(BYTE *aKeyStr)
{
  BYTE lKVC[8];
  BYTE mode, key_id;
  BYTE *ptr;

  CheckPointerAddr(aKeyStr);

  mode    = aKeyStr[0];
  key_id  = aKeyStr[1];
  ptr     = &aKeyStr[2];  // start of key content;

  // check valid key index
  if (key_id >= MAX_DUKPTKEY_SUPPORT)
    return INVALID_HOST;

  // check encryption key with double key length
  if ((mode & 0x12) != 0x10)
    return INVALID_HOST;

  // flush and save base key
  DukptKeyReset(key_id);              //clear key set
  os_key_dukpt_key_inject(&gSecurData.s_dukpt[key_id], ptr);

  // Check KVC
  if (mode & KVC_EXIST) {
    memcpy(lKVC, ptr, 8);
    os_3deskey(ptr);
    os_3des(lKVC);
    if (memcmp(lKVC, ptr+16, 2))
      return KVC_ERR;
  }
  UpdateSecurData();
  os_rand(lKVC);
  return CMD_OK;
}
//*****************************************************************************
//  Function        : GetPinDukpt
//  Description     : Get DUKPT PIN block
//  Input           : N/A
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
WORD DukptGetPin(BYTE *aPINBlock, BYTE *aPromptMsg, BYTE aKeyIdx)
{
  BYTE kbdbuf[256];
  BYTE pinblock[16];
  BYTE lKSN[10];

  CheckPointerAddr(aPINBlock);
  CheckPointerAddr(aPromptMsg);

  if (aKeyIdx >= MAX_DUKPTKEY_SUPPORT)
    return INVALID_HOST;

  if (gSecurData.s_dukpt[aKeyIdx].s_KSN[1] == NOT_INJECTED)
    return NOT_INJECTED;

  memset(pinblock, '0', 16);
  split(&kbdbuf[1], aPINBlock, 10);
  kbdbuf[0] = (BYTE)fndb(&kbdbuf[1], 'F', 20);
  if (kbdbuf[0] <= 12)
    memcpy(&pinblock[4+(12-kbdbuf[0])], &kbdbuf[1], kbdbuf[0]);
  else
    memcpy(&pinblock[4], &kbdbuf[kbdbuf[0]-12], 12);        // Veriform Format

  compress(pinblock, pinblock, 8);

  if (UseExtPPad()) {
    kbdbuf[0] = GETPIN_TIMEOUT;     // timeout
    kbdbuf[1] = 0x00;               // Mode
    memset(&kbdbuf[2], '0', 13);    // dummy data
    memset(&kbdbuf[15], 0x00, 6);   // Amount
    strcpy(&kbdbuf[21], aPromptMsg);
    kbdbuf[21+strlen(aPromptMsg)] = 0;
    if (SChnlGetPin(kbdbuf, (22 + strlen(aPromptMsg))) != 0)
      return RESP_KEY_CANCEL;
  }
  else {
    ClrBelow(K_Line3);
    os_disp_puts(aPromptMsg);

    kbdbuf[0] =0;
    while (kbdbuf[0] < 4) {
      kbdbuf[0] =0;
      if (!GetKbd(HIDE_NUMERIC+NULL_ENB+SU_BIGFONT+SU_LINE7+RIGHT_JUST, IMIN(4)+IMAX(12), kbdbuf))    // 100 01100  Min 4, Max 12
        return CMD_CANCEL;
    }
  }

  memset(&kbdbuf[1+kbdbuf[0]],'F',14-kbdbuf[0]);
  compress(&kbdbuf[1],&kbdbuf[1],7);
  memxor(pinblock, kbdbuf, 8);  //pinblock ready for encryption

  if (os_key_dukpt_encrypt(&gSecurData.s_dukpt[aKeyIdx], pinblock, lKSN)) {
    memcpy(aPINBlock, pinblock, 8);
    UpdateSecurData();  // Save the KSN for next GETPIN
    return CMD_OK;
  }

  os_rand(&pinblock[0]);
  os_rand(&pinblock[8]);
  return DUKPT_HALT;
}

